<?php
Cinnamon::loadClass('ICollection');

class DatabaseCollection implements ICollection {
	protected $db;
	protected $result;
	
	protected $source;
	
	protected $index;
	protected $object;
	
	/**
	 * Creates an instance of DatabaseCollection by using the specified database adapter and table. Fields can be optionally specified.
	 * @param DatabaseAdapter $db the database adapter to be used for executing database queries
	 * @param string $table the name of the table to be selected
	 * @param string $fields comma-separated fields to be selected
	 */
	public function __construct($db, $table, $fields=null) {
		$this->source = array(
			'select' 	=> null,
			'from' 		=> null,
			'where' 	=> null,
			'group' 	=> null,
			'order' 	=> null,
			'limit' 	=> null
		);
		
		$this->db = $db;
		$this->table($table);
		$this->fields($fields);
	}
	
	private function _initialize() {		
		//echo $sql;
		$sql = $this->_getSQL();
		$this->db->query($sql);
		$this->resource = $this->db->lastResource();
		$this->index = 0;
		$this->object = null;
	}
	
	protected function _getSQL() {
		$sql = 'SELECT '. $this->source['select'] .' FROM '. $this->source['from'];

		// apply filters
		Cinnamon::registry('filters')->filter($this);
		
		// identify tables
		//$tables = explode(',', $this->source['from']); 	// FIX: take care of nicknames
		//$conditions = Cinnamon::registry('filters')->getConditionsFor($tables);
		//if ( !empty($this->source['where']) )  {
		//	$conditions = '('. $conditions .') AND ('. $this->source['where'] .')';
		//}

		if ( !empty($this->source['where']) ) {
			$sql .=' WHERE '. $this->source['where'];
		}
		if ( !empty($this->source['group']) ) {
			$sql .=' GROUP BY '. $this->source['group'];
		}
		if ( !empty($this->source['order']) ) {
			$sql .=' ORDER BY '. $this->source['order'];
		}	
		if ( !empty($this->source['limit']) ) {
			$sql .=' LIMIT '. $this->source['limit'];
		}
		return $sql;
	}
	
	public function getDatabaseAdapter() {
		return $this->db;
	}
	
	public function getTable() {
		return $this->source['from'];
	}
	
	public function fields($fields) {
		if ( !empty($fields) )
			$this->source['select'] = $fields;
		return $this;
	}
	
	public function field($field) {
		if ( !empty($field) )
			$this->source['select'] .= ( empty($this->source['select']) ) ? $field : ', '. $field;
		return $this;
	}
	
	/**
	 * Alias for method fields
	 * @see DatabaseCollection::fields()
	 */
	public function select($fields) {
		return $this->fields($fields);
	}
	
	public function table($table) {
		$this->source['from'] = $table;
		return $this;
	}
	
	/**
	 * Alias for table
	 * @see DatabaseCollection::table()
	 */
	public function from($table) {
		return $this->table($table);
	}
	
	/**
	 * @see ICollection::filter()
	 */
	public function filter($filter) {
		if ( func_num_args() > 1 ) {
			$value = func_get_arg(1);		
			$value = Cinnamon::registry('db')->escape($value);
			// replace question mark with the value
			$filter = str_replace('?', '\''. $value .'\'', $filter);
		}
		$this->source['where'] .= ( empty($this->source['where']) ) ? $filter : ' AND '. $filter ;
		return $this;
	}
	
	/**
	 * @see ICollection::sort()
	 */
	public function sort($field, $order='ASC') {
		if ( !empty($this->source['order']) )
			$this->source['order'] .= ', ';
		$this->source['order'] .= $field .' '. $order;
		return $this;
	}
	
	/**
	 * Alias for sort
	 * @see DatabaseCollection::sort()
	 */
	public function order($field, $order='ASC') {
		return $this->sort($field, $order);
	}
	
	/**
	 * @see ICollection::slice()
	 */
	public function slice($offset, $length) {
		$this->source['limit'] = $offset .','. $length;
		return $this;
	}
	
	/**
	 * Alias for slice
	 * @see DatabaseCollection::slice()
	 */
	public function limit($offset, $length) {
		return $this->slice($offset, $length);
	}
	
	public function group($fields) {
		$this->source['group'] = $fields;
		return $this;
	}
	
	/**
	 * @see ICollection::getItemAt()
	 */
	public function getItemAt($i) {
		$this->_initialize();
		$item = null;
		$jstop = @mysql_num_fields($this->resource);
		for ( $j=0; $j<$jstop; $j++ ) {
			$field = @mysql_field_name($this->resource, $j);
			$item->{$field} = @mysql_result($this->resource, $i, $j);
		}
		return $item;
	}
	
	/**
	 * @see ICollection getValueAt()
	 */
	public function getValueAt($i, $field) {
		$this->_initialize();
		return @mysql_result($this->resource, $i, $field);
	}
	
	/**
	 * @see ICollection size()
	 */
	public function size() {
		if ( !is_resource($this->resource) ) {
			$sql = $this->_getSQL();
			$sql = 'SELECT COUNT(*) FROM ('. $sql .') AS cse';
			$this->db->query($sql);
			$size = $this->db->getValue();
			return $size;
		}
		return @mysql_num_rows($this->resource);
	}
	
	public function rewind() {
		$this->_initialize();
		@mysql_data_seek($this->resource, $this->key);
	}
	
	public function current() {
		if ( $this->object == null )
			$this->object = @mysql_fetch_object($this->resource);
		return $this->object;
	}
	
	public function key() {
		return $this->index;
	}
	
	public function next() {
		if ( $this->index == $this->size() ) {
			$this->object = false;
		} else {
			$this->object = @mysql_fetch_object($this->resource);
			$this->index++;		
		}
		return $this->object;
	}
	
	public function valid() {
		return ( $this->index < $this->size() );
	}
}
?>